﻿using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Globalization;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Web;
using System.IO;
using System.Web.UI.WebControls;
using System.ComponentModel;
using System.Collections;

namespace InterpriseSuiteEcommerceCommon.Extensions
{
    public static class AppExtensions
    {
        //Format sql quote string
        public static string FormatSqlQuote(this string s)
        {
            if (s == null) return "''";
                
            int len = s.Length + 25;
            var tmpS = new StringBuilder(len); // hopefully only one alloc

            tmpS.Append("N'");
            tmpS.Append(s.Replace("'", "''"));
            tmpS.Append("'");
            return tmpS.ToString();
        }   

        //shortcut of String.Format
        public static string FormatWith(this string s, params object[] args)
        {
            return string.Format(s, args);
        }

        public static bool? TryParseBool (this string str)
        {
            bool? ret = null;
            if (str == string.Empty) return ret;

            //if value is 1 or 0
            int? intValue = str.TryParseInt();
            if(intValue.HasValue && intValue.Value < 2)
            {
                return Convert.ToBoolean(intValue.Value);
            }

            //if value true or false
            if (str.ToLowerInvariant() == "true") return true;

            if (str.ToLowerInvariant() == "false") return false;

            return ret;
        }

        public static bool TryParseBool(this int? intValue)
        {
            bool ret = false;
            if (intValue == null) return ret;
            if (intValue.Value < 2)
            {
                ret = Convert.ToBoolean(intValue.Value);
            }
            return ret;
        }

        public static int? TryParseInt(this object obj)
        {
            return (obj == DBNull.Value || obj == null) ? null : obj.ToString().TryParseInt();
        }

        public static DateTime? TryParseDateTime(this string str)
        {
            DateTime dt = DateTime.MinValue;
            DateTime.TryParse(str, out dt);
            if (dt == DateTime.MinValue) return null;
            return dt;
        }

        public static DateTime? TryParseDateTime(this object obj)
        {
            return (obj == DBNull.Value || obj == null) ? null : obj.ToString().TryParseDateTime();
        }

        //Compare 2 string ignore case
        public static bool EqualsIgnoreCase(this string s, string matchWith)
        {
            return s.Equals(matchWith, StringComparison.OrdinalIgnoreCase);
        }

        //parse string if int32 else return 0
        public static bool IsInt32(this string s)
        {
            int x;
            return int.TryParse(s, out x);
        }

        public static TEnum TryParseEnum<TEnum>(this string enumname)
        {
            return (TEnum)Enum.Parse(typeof(TEnum), enumname, true);
        }

        //parse string if int32 else return null
        public static int? TryParseInt(this string str)
        {
            int xValue;
            if (int.TryParse(str, out xValue))
            {
                return xValue;
            }
            return null;
        }

        //check if value is in between the start and end Int value
        public static bool Between(this int n, int start, int end)
        {
            return n >= start && n <= end;
        }

        //check if value is in between the start and end Date value
        public static bool Between(this DateTime n, DateTime start, DateTime end)
        {
            return n >= start && n <= end;
        }

        //check if value is in the collection
        public static bool In(this int n, params int[] sequence)
        {
            return sequence.Any(x => x == n);
        }

        //pick a specified items in the collection.
        public static IEnumerable<T> Pick<T>(this IEnumerable<T> collection, Func<T, bool> when)
        {
            var items = new List<T>();
            foreach (var item in collection)
            {
                if (when(item))
                {
                    items.Add(item);
                }
            }

            return items;
        }

        
        /// <summary>
        /// shuffles the items in the collection
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="source"></param>
        /// <param name="random"></param>
        /// <returns></returns>
        public static IEnumerable<T> Shuffle<T>(this IEnumerable<T> source, Random random)
        {
            var buffer = source.ToList();

            for (int i = 0; i < buffer.Count; i++)
            {
                int j = random.Next(i, buffer.Count);
                yield return buffer[j];

                buffer[j] = buffer[i];
            }
        }

        //parse string if decimal else return 0
        public static decimal? TryParseDecimal(this string str)
        {
            decimal xValue;
            if (decimal.TryParse(str, out xValue))
            {
                return xValue;
            }
            return null;
        }

        //parse string if float else return 0
        public static float? TryParseFloat(this string str)
        {
            float xValue;
            if (float.TryParse(str, out xValue))
            {
                return xValue;
            }
            return null;
        }

        //parse string if float else return 0
        public static long? TryParseLong(this string str)
        {
            long xValue;
            if (long.TryParse(str, out xValue))
            {
                return xValue;
            }
            return null;
        }

        public static DateTime? TryParseDataTimeLocalized(this string strDateTime, CultureInfo cultureInfo) 
        {
            var dateFormat = cultureInfo.DateTimeFormat.Clone() as DateTimeFormatInfo;
            DateTime? dte = null;
            DateTime xdte = DateTime.MinValue;
            if (DateTime.TryParseExact(strDateTime, dateFormat.FullDateTimePattern, cultureInfo, DateTimeStyles.None, out xdte))
            {
                dte = xdte;
            }
            return dte;
        }

        public static Guid? TryParseGuid(this string str)
        {
            Guid guid;
            if(Guid.TryParse(str, out guid))
            {
                return guid;
            }
            return null;
        }

        //Direct string parsing
        public static bool IsNullOrEmptyTrimmed(this string str)
        {
            if (str != null) str = str.Trim();
            return string.IsNullOrEmpty(str);
        }

        //Direct string parsing
        public static bool IsNullOrEmpty(this string str)
        {
            return string.IsNullOrEmpty(str);
        }

        //Direct object parsing
        public static bool IsNullOrEmptyTrimmed(this object str)
        {
            string temp = string.Empty;
            if (str != null) temp = str.ToString().Trim();
            return string.IsNullOrEmpty(temp);
        }
        
        public static void ForEach<T> (this IEnumerable<T> collection, Action<T> cAction)
        {
            foreach (var item in collection)
            {
                cAction(item);
            }
        }

        public static string ToMungeName(this string str, string regex = "[^a-z0-9-_ ]", string otherFormat = "[\\.\\@\\$\\%\\^\\*\\]\\&\\!\\+\\=\\#\\[\\~\\`\\(\\)]")
        {
            string strToFormat = Regex.Replace(str.Trim().ToLowerInvariant(), otherFormat, "");
            strToFormat = Regex.Replace(strToFormat.Trim().ToLowerInvariant(), regex, "-").Replace(" ", "-");
            while (strToFormat.IndexOf("--") != -1) { strToFormat = strToFormat.Replace("--", "-"); }
            while (strToFormat.IndexOf("__") != -1) { strToFormat = strToFormat.Replace("__", "_"); }
            return HttpUtility.UrlEncode(strToFormat);
        }

        public static string ToHtmlDecode(this string str)
        {
            return HttpUtility.HtmlDecode(str);
        }

        public static string ToHtmlEncode(this string str)
        {
            return HttpUtility.HtmlEncode(str);
        }

        public static string ToUrlDecode(this string str)
        {
            return HttpUtility.UrlDecode(str);
        }

        public static string ToUrlEncode(this string str)
        {
            return HttpUtility.UrlEncode(str);
        }

        public static string ToDriverLink(this string str) 
        {
            return "t-{0}.aspx".FormatWith(str).ToLowerInvariant();
        }

        public static string ToQueryString(this string str)
        {
            string tmpS = string.Empty;
            if (!string.IsNullOrEmpty(HttpContext.Current.Request.QueryString[str]))
            {
                tmpS = HttpContext.Current.Request.QueryString[str];
            }
            return tmpS;
        }

        public static string ToQueryStringDecode(this string str ){
             return str.ToQueryString().ToUrlDecode();
        }

        public static string ToQueryStringEncode(this string str)
        {
            return str.ToQueryString().ToUrlEncode();
        }

        public static int? TryParseIntLocalization(this string str, CultureInfo cultureInfo)
        { 
            int usi = 0;
            Int32.TryParse(str, NumberStyles.Integer, cultureInfo, out usi); // use default locale setting
            if (usi == 0) return null;
            return usi;
        }

        public static decimal? TryParseDecimalLocalization(this string str, CultureInfo cultureInfo)
        {
            decimal usi = 0;
            Decimal.TryParse(str, NumberStyles.Integer, cultureInfo, out usi); // use default locale setting
            if (usi == 0) return null;
            return usi;
        }

        public static decimal? TryParseDecimalUsLocalization(this string str)
        {
            return str.TryParseDecimalLocalization(new CultureInfo("en-US"));
        }

        public static int? TryParseIntUsLocalization(this string str)
        {
            return str.TryParseIntLocalization(new CultureInfo("en-US"));
        }

        public static string ToSubString(this string str, int value)
        {
            if (str.Length <= value) return str;
            else return str.Substring(0, value - 1);
        }

        public static IEnumerable<KeyValuePair<string, string>> ToPairs(this NameValueCollection collection)
        {
            if (collection == null)
            {
                throw new ArgumentNullException("collection");
            }
            return collection.Cast<string>().Select(key => new KeyValuePair<string, string>(key, collection[key]));
        }

        public static IEnumerable<KeyValuePair<DictionaryEntry, object>> HashToPairs(this Hashtable collection, bool useParallel = false)
        {
            if (collection == null)
            {
                throw new ArgumentNullException("collection");
            }

            if (useParallel)
            {
                return collection.Cast<DictionaryEntry>().Select(key => new KeyValuePair<DictionaryEntry, object>(key, collection[key])).AsParallel();
            }
            else
            {
                return collection.Cast<DictionaryEntry>().Select(key => new KeyValuePair<DictionaryEntry, object>(key, collection[key]));
            }
        }

        public static string ToPathFromFileOrPath(this string fileOrpath, bool includeBackslash = false)
        {
            string path = fileOrpath;
            if (File.Exists(fileOrpath))
            {
                var fileInfo = new FileInfo(fileOrpath);
                path = fileInfo.Directory.FullName;
            }
            // Handle special cases like resource(axd) and Rewritted URLs(aspx) which is not a valid file.
            else if (fileOrpath.EndsWith(".aspx"))
            {
                //Get the directory leaving the invalid file
                path = fileOrpath.Substring(0, fileOrpath.LastIndexOf(@"\"));
            }

            if (!includeBackslash) return path;
            
            if (!path.EndsWith(@"\"))
            {
                path += @"\";
            }

            return path;
        }

        public static string ToStringLower(this bool condition) 
        {
            return condition.ToString().ToLowerInvariant();    
        }

        public static T FindByParse<T>(this RepeaterItem item, string controlId) where T :class 
        {
            return item.FindControl(controlId) as T;
        }

        public static T DataItemAs<T>(this RepeaterItem repeaterItem) where T : class
        {
            return repeaterItem.DataItem as T;
        }

        public static string ToJSON(this IEnumerable array)
        {
            try
            {
                return InterpriseSuiteEcommerceCommon.Tool.JSONHelper.Serialize(array);
            }
            catch (Exception)
            {
                return string.Empty;
            }
        }

    }

    public static class EnumExtensions
    {
        public static IEnumerable<T> GetAllItems<T>()
        {
            return from object item in Enum.GetValues(typeof(T)) select (T)item;
        }
    }

    public static class DomainSecurityExtension
    { 
        public static string ToJavaScriptEscape(this string value)
        {
            var sb = new StringBuilder(value);
            sb.Replace("\b", string.Empty);
            sb.Replace("\f", string.Empty);
            sb.Replace("\n", string.Empty);
            sb.Replace("\r", string.Empty);
            sb.Replace("\t", string.Empty);
            sb.Replace("'", @"\\'");
            sb.Replace("\"", "\\\"");

            return sb.ToString();
        }
    }

    public static class DBExtensions
    {
        public static string ToDbQuote(this string value)
        {
            if (value == null) { return "''"; }
            int len = value.Length + 25;
            var tmpS = new StringBuilder(len); // hopefully only one alloc
            tmpS.Append("N'");
            tmpS.Append(value.Replace("'", "''"));
            tmpS.Append("'");
            return tmpS.ToString();
        }

        public static string ToDbDateQuote(this string s)
        {
            int len = s.Length + 25;
            var tmpS = new StringBuilder(len); // hopefully only one alloc
            tmpS.Append("'");
            tmpS.Append(s.Replace("'", "''"));
            tmpS.Append("'");
            return tmpS.ToString();
        }

    }
}
